﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml.Linq;
using GalaSoft.MvvmLight.Command;
using Microsoft.Win32;
using Veralkohol.Commons;
using System.Windows.Threading;
using Veralkohol.BAMTService;
using System.Windows.Controls;
using System.Xml.Serialization;
using System.Xml;

namespace Veralkohol.ViewModel
{
    public class MainViewModel : VMAbstract
    {
        public ObservableCollection<AlcoholDiagramPoint> Points { get; set; }
        private DispatcherTimer timer;
        private double appstart = 0;
        private int appstartday = 0;

        public double[] opac = { 1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 };
        public double[] Opac
        {
            get { return opac; }
            set { opac = value; NotifyPropertyChanged("Opac"); }
        }

        double weight;
        public double Weight
        {
            get { return weight; }
            set { weight = value; NotifyPropertyChanged("Weight"); }
        }

        double percentage;
        public double Percentage
        {
            get { return percentage; }
            set { percentage = value; NotifyPropertyChanged("Percentage"); }
        }

        double quantity;
        public double Quantity
        {
            get { return quantity; }
            set { quantity = value; NotifyPropertyChanged("Quantity"); }
        }

        int day;
        public int Day
        {
            get { return day; }
            set { day = value; NotifyPropertyChanged("Day"); }
        }

        int hours;
        public int Hours
        {
            get { return hours; }
            set { hours = value; NotifyPropertyChanged("Hours"); }
        }

        int minutes;
        public int Minutes
        {
            get { return minutes; }
            set { minutes = value; NotifyPropertyChanged("Minutes"); }
        }

        string xfrom;
        public string XFrom
        {
            get { return xfrom; }
            set { xfrom = value; NotifyPropertyChanged("XFrom"); }
        }

        string xto;
        public string XTo
        {
            get { return xto; }
            set { xto = value; NotifyPropertyChanged("XTo"); }
        }

        double yfrom;
        public double YFrom
        {
            get { return yfrom; }
            set { yfrom = value; NotifyPropertyChanged("YFrom"); }
        }

        double yto;
        public double YTo
        {
            get { return yto; }
            set { yto = value; NotifyPropertyChanged("YTo"); }
        }

        bool realtime;
        public bool Realtime
        {
            get { return realtime; }
            set { realtime = value; NotifyPropertyChanged("Realtime"); NotifyPropertyChanged("NotRealtime"); }
        }
        public bool NotRealtime
        {
            get { return !realtime; }
            set { realtime = value; }
        }

        bool nopoint;
        public bool NoPoint
        {
            get { return nopoint; }
            set { nopoint = value; NotifyPropertyChanged("NoPoint"); }
        }

        public string Drinkname { get; set; }
        public string Imagename { get; set; }

        public MainViewModel()
        {
            Points = new ObservableCollection<AlcoholDiagramPoint>();
            Weight = 60;
            Hours = DateTime.Now.Hour;
            Minutes = DateTime.Now.Minute;
            Day = 0;
            Percentage = 0;
            Quantity = 1;
            XFrom = "Auto";
            XTo = "Auto";
            YFrom = 0;
            YTo = 10;
            Realtime = false;
            appstart = (DateTime.Now.Day - DateTime.Now.Day) * 24 + DateTime.Now.Hour + (double)DateTime.Now.Minute / 60;
            appstartday = DateTime.Now.Day;

            NoPoint = true;

            timer = new DispatcherTimer();
            int tickminute = 2;
            timer.Interval = TimeSpan.FromSeconds(tickminute);
            timer.Tick += (s, e) =>
                {
                    Points.Add(new AlcoholDiagramPoint(Weight, Points[Points.Count - 1].ComparableDrinkTime + tickminute * 5));
                    if (Points.Last().Thousandths <= 0.03)
                    {
                        timer.Stop();
                        Realtime = false;
                    }
                };
        }

        private void calcOpacity()
        {
            try
            {
                double val = Points.Last().Thousandths;
                if (val <= 0.03) Opac = new[] { 1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 };
                else if (val <= 0.5) Opac = new[] { 0.1, 1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 };
                else if (val <= 1.5) Opac = new[] { 0.1, 1, 1, 0.1, 0.1, 0.1, 0.1, 0.1 };
                else if (val <= 2.5) Opac = new[] { 0.1, 1, 1, 1, 0.1, 0.1, 0.1, 0.1 };
                else if (val <= 3.5) Opac = new[] { 0.1, 1, 1, 1, 1, 0.1, 0.1, 0.1 };
                else if (val <= 4.5) Opac = new[] { 0.1, 1, 1, 1, 1, 1, 1, 0.1 };
                else Opac = new[] { 0.1, 1, 1, 1, 1, 1, 1, 1 };
            }
            catch
            {
                Opac = new[] { 1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1 };
            }
        }

        private void diagramize(PersistentDiagram diagr)
        {
            if (diagr != null)
            {
                timer.Stop();
                Realtime = false;
                Points.Clear();
                XFrom = diagr.xfrom;
                XTo = diagr.xto;
                NoPoint = true;
                YFrom = diagr.yfrom;
                YTo = diagr.yto;
                foreach (var item in diagr.Drunked)
                {
                    foreach (var item2 in item.drinks)
                    {
                        Points.Add(new AlcoholDiagramPoint(
                            diagr.weight, item2.quantity, item2.percentage,
                            item.day, item.hour, item.minute,
                            item2.drinkname, item2.imagename));
                    }
                }
            }
        }

        RelayCommand add;
        public RelayCommand Add
        {
            get
            {
                return NewRCommand(add,
                    () =>
                    {
                        if (Realtime)
                        {
                            double nowtime = (DateTime.Now.Day - appstartday) * 24 + DateTime.Now.Hour + (double)DateTime.Now.Minute / 60;
                            Points.Add(new AlcoholDiagramPoint(Weight, Quantity, Percentage, nowtime, Drinkname, Imagename));
                        }
                        else
                        {
                            Points.Add(new AlcoholDiagramPoint(Weight, Quantity, Percentage, Day, Hours, Minutes, Drinkname, Imagename));
                        }
                        NoPoint = false;
                    }
                );
            }
        }

        RelayCommand newb;
        public RelayCommand New
        {
            get
            {
                return NewRCommand(newb,
                    () =>
                    {
                        timer.Stop();
                        Realtime = false;
                        Points.Clear();
                        XFrom = "Auto";
                        XTo = "Auto";
                        NoPoint = true;
                    }
                );
            }
        }

        RelayCommand diagramchangedcommand;
        public RelayCommand DiagramChangedCommand
        {
            get
            {
                return NewRCommand(diagramchangedcommand,
                    () =>
                    {
                        calcOpacity();
                    }
                );
            }
        }

        RelayCommand<SelectionChangedEventArgs> selchanged;
        public RelayCommand<SelectionChangedEventArgs> SelectionChanged
        {
            get
            {
                return NewRCommand<SelectionChangedEventArgs>(selchanged,
                    (param) =>
                    {
                        Percentage = (param.AddedItems[0] as ToResources).Percentage;
                        Drinkname = (param.AddedItems[0] as ToResources).DrinkName;
                        Imagename = (param.AddedItems[0] as ToResources).ImageName;
                    }
                );
            }
        }

        RelayCommand realt;
        public RelayCommand Realt
        {
            get
            {
                return NewRCommand(realt,
                    () =>
                    {
                        if (Points.Count == 0)
                        {
                            MessageBox.Show("Először meg kell adni a kezdőpontot!");
                            return;
                        }
                        if (Realtime)
                        {
                            Realtime = false;
                            timer.Stop();
                        }
                        else
                        {
                            Realtime = true;
                            timer.Start();
                        }

                    }
                );
            }
        }

        RelayCommand save;
        public RelayCommand Save
        {
            get
            {
                return NewRCommand(save,
                    () =>
                    {
                        string messageBoxText = "Szeretnéd feltölteni az adatokat a szerverre?\nA \"No\" választásával a saját számítógépedre mentheted az adatokat.";
                        string caption = "Mentés";
                        MessageBoxButton button = MessageBoxButton.YesNoCancel;
                        MessageBoxImage icon = MessageBoxImage.Question;
                        MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);

                        #region Create Persistence Object

                        var diagr = new PersistentDiagram();
                        diagr.Drunked = new List<PersistentAlcoholicData>();
                        diagr.xto = XTo;
                        diagr.xfrom = XFrom;
                        diagr.yto = YTo;
                        diagr.yfrom = YFrom;
                        diagr.weight = Weight;
                        foreach (var item in Points.Where((p) => p.isControlPoint))
                        {
                            diagr.Drunked.Add(new PersistentAlcoholicData()
                            {
                                day = (int)(item.DrinkTime / 24),
                                hour = (int)(item.DrinkTime - ((int)(item.DrinkTime / 24)) * 24),
                                minute = (int)Math.Round((item.DrinkTime - ((int)(item.DrinkTime / 24)) * 24 - ((int)(item.DrinkTime - ((int)(item.DrinkTime / 24)) * 24))) * 60, 0),

                                drinks = item.Drinks.Select((p) => new PersistentDrink()
                                {
                                    drinkname = p.Drinkname,
                                    imagename = p.ImageName,
                                    percentage = p.Percentage,
                                    quantity = p.Quantity
                                }).ToList()
                            });
                        }

                        #endregion


                        // Process message box results 
                        switch (result)
                        {
                            case MessageBoxResult.Yes:
                                new RemotePersistence().Save(diagr);
                                break;
                            case MessageBoxResult.No:
                                new LocalPersistence().Save(diagr);
                                break;
                            case MessageBoxResult.Cancel:
                                break;
                        }
                    }
                );
            }
        }

        RelayCommand load;
        public RelayCommand Load
        {
            get
            {
                return NewRCommand(load,
                    () =>
                    {
                        string messageBoxText = "Szeretnéd a szerveről betölteni az adatokat?\nA \"No\" választásával a saját számítógépről töltheted be az adatokat.";
                        string caption = "Megnyitás";
                        MessageBoxButton button = MessageBoxButton.YesNoCancel;
                        MessageBoxImage icon = MessageBoxImage.Question;
                        MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);

                        // Process message box results 
                        switch (result)
                        {
                            case MessageBoxResult.Yes:
                                new OpenServer().ShowDialog();
                                var diagr2 = new RemotePersistence().Load();
                                diagramize(diagr2);
                                break;
                            case MessageBoxResult.No:
                                var diagr = new LocalPersistence().Load();
                                diagramize(diagr);
                                break;
                            case MessageBoxResult.Cancel:
                                break;
                        }
                    }
                );
            }
        }
    }
}
